/**
 * 
 */
package com.wgo.precise.server.web.servlet;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.wgo.bpot.common.transport.exception.RematoException;
import com.wgo.bpot.common.transport.util.DomainModelTypeNamingConvention;
import com.wgo.bpot.server.persist.BasicPersistService;
import com.wgo.precise.server.service.PreciseServiceServerImpl;

/**
 * @author peide3
 *
 */
public class PreciseServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	private static Logger logger = Logger.getLogger(PreciseServlet.class);

	private PreciseServiceServerImpl preciseService;
	
	/**
	 * @param preciseService The preciseService to set.
	 */
	public void setPreciseService(PreciseServiceServerImpl preciseService) {
		this.preciseService = preciseService;
	}

	@Override
	public void destroy() {
		preciseService = null;
		super.destroy();
	}

	@Override
	public void init() throws ServletException {
		super.init();
		preciseService = new PreciseServiceServerImpl();
		try {
			String persistClassName = getInitParameter("persistence-class");
			if (null != persistClassName) {
				Class<BasicPersistService> persistenceClass = DomainModelTypeNamingConvention.<BasicPersistService>loadClass(persistClassName);
				preciseService.setPersistService(persistenceClass.newInstance());
			}
		} catch (Exception e) {
			logger.error("Error while initializing servlet. " + e.getMessage(), e);
		}
	}
	


	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		ObjectInputStream inputStream = new ObjectInputStream(new BufferedInputStream(req.getInputStream()));
		Object returnValue = null;
		Throwable throwable = null;
		try {
			String methodName = (String) inputStream.readObject();
			Class[] classParameters = (Class[]) inputStream.readObject();
			Method method = preciseService.getClass().getMethod(methodName, classParameters);
			Object[] args = (Object[]) inputStream.readObject();
//			try {
				returnValue = method.invoke(preciseService, args);
//			} catch (IllegalArgumentException e) {
//				MethodAccessor methodAccessor = MethodAccessorAcquirerer.getMethodAccessor(method);
//				returnValue = methodAccessor.invoke(preciseService, args);
//			}
		} catch (InvocationTargetException e) {
			throwable = e.getTargetException();
		} catch (RematoException e) {
			if (e.getCause() != null) {
				throwable = e.getCause();
			} else {
				throwable = e;
			}
		} catch (Exception e) {
			throwable = e;
		}
		if (null != throwable) {
			if (throwable instanceof RematoException && null != throwable.getCause()) { // TODO: clean up in ExceptionHierarchy, to be able to give reasonable errormessages to client..
				throwable = throwable.getCause();
			}
			returnValue = new RematoException(throwable.getMessage(), throwable.getStackTrace());
			logger.error("Error invoking RPC.", throwable);
		}
		resp.setContentType("application/octet-stream");
		ObjectOutputStream outputStream = new ObjectOutputStream(new BufferedOutputStream(resp.getOutputStream()));
		outputStream.writeObject(returnValue);
		outputStream.flush();
		outputStream.close();
	}


}
